﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using JXT.PrimaryKey.Batman.Domain.Models;

namespace JXT.PrimaryKey.Batman.Domain.Specifications.Expressions
{
    internal class QueryExpressionVisitor<TEntity> : ExpressionVisitor
        where TEntity : IEntity {
        private ParameterExpression _parameterExpression;

        private Expression<Func<TEntity, bool>> expression;

        public QueryExpressionVisitor(Expression<Func<TEntity, bool>> whereExpression)
        {
            expression = whereExpression;
        }

        public Expression<Func<TEntity, bool>> Convert(Expression<Func<TEntity, bool>> startExpression, ParameterExpression parameterExpression, WhereType appendType = WhereType.And)
        {
            //parameterExpression = Expression.Parameter(typeof(TResult), "e");
            _parameterExpression = parameterExpression;
            var result = Visit(expression);
            Expression bodyExpression;
            if (appendType == WhereType.And)
                bodyExpression = Expression.And(startExpression.Body, ((LambdaExpression)result).Body);
            else if (appendType == WhereType.Or)
                bodyExpression = Expression.Or(startExpression.Body, ((LambdaExpression)result).Body);
            else
                bodyExpression = ((LambdaExpression)result).Body;
            return Expression.Lambda<Func<TEntity, bool>>(bodyExpression, parameterExpression);
        }

        protected override Expression VisitParameter(ParameterExpression p) {
            var baseResult = base.VisitParameter(p);
            return _parameterExpression;
        }

        protected override Expression VisitBinary(BinaryExpression b) {
            switch (b.NodeType) {
                case ExpressionType.Equal:
                    return Expression.Equal(base.Visit(b.Left), b.Right);
                case ExpressionType.NotEqual:
                    return Expression.NotEqual(base.Visit(b.Left), b.Right);
                case ExpressionType.LessThan:
                    return Expression.LessThan(base.Visit(b.Left), b.Right);
                case ExpressionType.LessThanOrEqual:
                    return Expression.LessThanOrEqual(base.Visit(b.Left), b.Right);
                case ExpressionType.GreaterThan:
                    return Expression.GreaterThan(base.Visit(b.Left), b.Right);
                case ExpressionType.GreaterThanOrEqual:
                    return Expression.GreaterThanOrEqual(base.Visit(b.Left), b.Right);
                default:
                    return base.VisitBinary(b);
            }
        }

        //otected override Expression VisitMemberAccess(MemberExpression m) {
            //var baseResult = base.VisitMemberAccess(m);
            //if (m.Member.ReflectedType.IsSubclassOf(typeof(EntityBase))) {
            //    var objectAttributes = m.Member.GetCustomAttributes(typeof(ObjectAttribute), false) as ObjectAttribute[];
            //    string name;
            //    if (objectAttributes != null && objectAttributes.Length > 0) {
            //        name = objectAttributes[0].Name;
            //    } else {
            //        name = m.Member.Name;
            //    }
            //    var subExpression = Visit(m.Expression);
            //    var subPropertyExpression = Expression.Property(subExpression, name);
            //    return subPropertyExpression;
            //} else {
            //    var columnAttributes = m.Member.GetCustomAttributes(typeof(ColumnAttribute), false) as ColumnAttribute[];
            //    string name;
            //    if (columnAttributes != null && columnAttributes.Length > 0) {
            //        name = columnAttributes[0].Name;
            //    } else {
            //        name = m.Member.Name;
            //    }
            //    return base.VisitMemberAccess(m);
            //    //var propertyExpression = Expression.Property(parameterExpression, name);
            //    //Expression.MakeMemberAccess(
            //    //return propertyExpression;
            //}
        //}
    }
}
